package system

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"jgyApi/server/global"
	"jgyApi/server/model/common/response"
	"jgyApi/server/model/system"
	systemReq "jgyApi/server/model/system/request"
	systemRes "jgyApi/server/model/system/response"
	system2 "jgyApi/server/service/system"
	"jgyApi/server/utils"
	"net/http"
	"strings"
	"time"
)

type SnApi struct{}

//
// GetSnTag
//  @Description:获取sn所属批次
//  @receiver s
//  @param c
//
func (s *SnApi) GetSnTag(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var sn system.Sn
	sn.Value = co.Sn
	err = global.GVA_DB.First(&sn).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(sn, c)
	return

}

//
// GetStudent
//  @Description: 获取sn所在的班级和批次
//  @receiver s
//  @param c
//
func (s *SnApi) GetStudent(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	type result struct {
		Value      string  `gorm:"column:value;type:varchar(255);not null;comment:SN码" json:"value"`
		Batch      string  `gorm:"column:batch;type:varchar(255);not null;comment:名称" json:"batch"`
		Realname   *string `gorm:"column:realname;type:varchar(50);comment:姓名;default:'';not null" json:"realname"`
		Classlevel *string `gorm:"column:classlevel;type:varchar(255);comment:班级" json:"classes"`
		Sno        *string `gorm:"column:sno;type:varchar(50);comment:学号" json:"sno"`
		AdminID    int64   `gorm:"column:admin_id;type:int(11) unsigned;not null;comment:sn码归属id" json:"admin_id"`
	}
	var sn result
	err = global.GVA_DB.Table("sn").Select("sn.id", "sn.value", "batch.batch", "sn.realname", "sn.classlevel", "sn.sno", "sn.admin_id").Joins("left join batch on batch.id = sn.batch").Where("sn.value = ?", co.Sn).First(&sn).Error

	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}

	var empty string
	if sn.Realname == nil {
		sn.Realname = &empty
	}
	if sn.Classlevel == nil {
		sn.Classlevel = &empty
	}
	response.OkWithData(sn, c)
	return
}

//
// GetSnTimeControl
//  @Description: sn获取时间管控
//  @receiver s
//  @param c
//
func (s *SnApi) GetSnTimeControl(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	if rs.Data == nil || rs.Data == "" {
		response.FailWithMessage("该设备没有设置批次", c)
		return
	}
	type result struct {
		StartTime *string `gorm:"column:start_time;type:varchar(10);comment:开启时间" json:"start_time"`
		EndTime   *string `gorm:"column:end_time;type:varchar(10);comment:结束时间" json:"end_time"`
	}
	var res result
	where := fmt.Sprintf("find_in_set(%s,batch)", rs.Data)
	err = global.GVA_DB.Model(system.TimeControl{}).Where(where).First(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(res, c)
	return

}

//
// DeleteAliases
//  @Description: 清除推送别名
//  @receiver s
//  @param c
//
func (s *SnApi) DeleteAliases(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	appKey := global.GVA_CONFIG.System.JpushAppKey
	masterSecret := global.GVA_CONFIG.System.JpushMasterSecret
	authBasic := base64.StdEncoding.EncodeToString([]byte(appKey + ":" + masterSecret))
	auth := []string{fmt.Sprintf("Basic %s", authBasic), "application/json"}
	client := &http.Client{}
	url := fmt.Sprintf("https://device.jpush.cn/v3/aliases/%s", co.Sn)
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		response.FailWithMessage("内部服务器错误", c)
		return
	}
	req.Header.Set("Authorization", auth[0])
	req.Header.Set("Content-Type", auth[1])
	resp, err := client.Do(req)
	if err != nil {
		response.FailWithMessage("内部服务器错误", c)
		return
	}
	if resp.StatusCode != 200 {
		errMsg := fmt.Sprintf("删除别名错误，错误码为%d", resp.StatusCode)
		response.FailWithMessage(errMsg, c)
	}
	defer resp.Body.Close()
	response.OkWithMessage("成功", c)
}

//
// GetSnScreen
//  @Description: 获取霸屏状态
//  @receiver s
//  @param c
//
func (s *SnApi) GetSnScreen(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	type result struct {
		IsScreenLock *int64  `gorm:"column:is_screen_lock;type:tinyint(1);comment:屏幕锁定   1锁定  0不锁定" json:"is_screen_lock"`
		LockContent  *string `gorm:"column:lock_content;type:varchar(255);default:因管控需要，该设备锁定中，请联系老师或管理员;comment:锁屏字幕" json:"lock_content"`
		Name         string  `json:"name"`
	}
	var res result
	err = global.GVA_DB.Model(&system.Sn{}).Where("value = ?", co.Sn).Select("is_screen_lock", "lock_content").First(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	if *res.IsScreenLock == 1 {
		res.Name = *res.LockContent
	}
	response.OkWithData(res, c)
	return
}

//
// GetSnDesktop
//  @Description: 获取桌面应用信息
//  @receiver s
//  @param c
//
func (s *SnApi) GetSnDesktop(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	if rs.Data == nil || rs.Data == "" {
		response.FailWithMessage("该设备没有设置批次", c)
		return
	}
	desk := struct {
		DesktopID int64 `gorm:"column:desktop_id;type:int(10);not null;comment:桌面编号" json:"desktop_id"`
	}{}
	where := fmt.Sprintf("find_in_set(%s,batch)", rs.Data)
	err = global.GVA_DB.Model(&system.DesktopControl{}).Where(where).First(&desk).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	var result system.Desktop
	err = global.GVA_DB.Model(&system.Desktop{}).First(&result, desk.DesktopID).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(result, c)
	return
}

//
// GetSnAppControl
//  @Description: 获取应用霸屏管控
//  @receiver s
//  @param c
//
func (s *SnApi) GetSnAppControl(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	if rs.Data == nil || rs.Data == "" {
		response.FailWithMessage("该设备没有设置批次", c)
		return
	}
	type result struct {
		AppID *int64 `gorm:"column:app_id;type:int(10);comment:应用编号" json:"app_id"`
	}
	var res []result
	where := fmt.Sprintf("find_in_set(%s,batch)", rs.Data)
	err = global.GVA_DB.Model(system.AppControl{}).Where(where).Find(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	appIdArr := make([]int64, len(res))
	for _, v := range res {
		appIdArr = append(appIdArr, *v.AppID)
	}

	type apps struct {
		Bg *string `gorm:"column:bg;type:varchar(255);comment:纯包名" json:"bg"`
	}
	var appResult []apps
	err = global.GVA_DB.Model(system.App{}).Where("app_id IN ?", appIdArr).Find(&appResult).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(appResult, c) //todo:这个接口要比较下原来的返回值
}

//
// GetSnAppTest
//  @Description: sn获取灰度测试
//  @receiver s
//  @param c
//
func (s *SnApi) GetSnAppTest(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	var where string
	if rs.Data == nil || rs.Data == "" {
		where = fmt.Sprintf("find_in_set('%s',sn_values)", co.Sn)
	} else {
		where = fmt.Sprintf("find_in_set('%s',sn_values) OR find_in_set('%s',batch)", co.Sn, rs.Data)
	}

	type versionCode struct {
		AppVersionCode *int64 `gorm:"column:app_version_code;type:int(11) unsigned;comment:应用内部版本" json:"app_version_code"`
	}
	var appTest []versionCode
	err = global.GVA_DB.Model(&system.AppTest{}).Where(where).Select("max(app_version_code) as app_version_code").Group("app_package").Find(&appTest).Error
	versionCodeArr := make([]int64, len(appTest))
	for _, v := range appTest {
		versionCodeArr = append(versionCodeArr, *v.AppVersionCode)
	}
	if len(versionCodeArr) == 0 {
		response.FailWithMessage("没有数据", c)
		return
	}

	type result struct {
		AppName        *string `gorm:"column:app_name;type:varchar(50);comment:应用名称" json:"app_name"`
		AppPackage     *string `gorm:"column:app_package;type:varchar(50);comment:应用包名" json:"app_package"`
		AppSize        *int64  `gorm:"column:app_size;type:int(12);comment:应用大小" json:"app_size"`
		AppVersionCode *int64  `gorm:"column:app_version_code;type:int(11) unsigned;comment:应用内部版本" json:"app_version_code"`
		AppURL         *string `gorm:"column:app_url;type:varchar(255);comment:应用地址" json:"app_url"`
		AppMd5         *string `gorm:"column:app_md5;type:varchar(50);comment:应用MD5" json:"app_md5"`
	}
	var res []result

	err = global.GVA_DB.Model(&system.AppTest{}).Where(where).Where("app_version_code IN ?", versionCodeArr).Find(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(res, c)
	return
}

//
// GetLogoImg
//  @Description: 获取开机logo图
//  @receiver s
//  @param c
//
func (s *SnApi) GetLogoImg(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	if rs.Data == nil || rs.Data == "" {
		response.FailWithMessage("该设备没有设置批次", c)
		return
	}

	type result struct {
		FileURL string  `gorm:"column:file_url;type:varchar(255);not null" json:"file_url"`
		FileMd5 *string `gorm:"column:file_md5;type:varchar(50);comment:文件md5" json:"file_md5"`
		Batch   *string `gorm:"column:batch;type:varchar(255)" json:"batch"`
	}
	var res result
	where := fmt.Sprintf("find_in_set('%s',batch)", rs.Data)
	err = global.GVA_DB.Model(&system.LogoImage{}).Select("file_url", "file_md5", "batch").Where(where).Order("id desc").Order("update_time desc").First(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(res, c)
	return
}

//
// getMac
//  @Description: 更新sn所属设备信息
//  @receiver s
//  @param c
//
func (s *SnApi) GetMac(c *gin.Context) {
	var co systemReq.GetMacSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.GetMacVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var sn system.Sn
	err = global.GVA_DB.Model(&system.Sn{}).Where("value = ?", co.Sn).First(&sn).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	sn.Mac = &co.Mac
	sn.LocalMac = &co.LocalMac
	sn.JpushID = &co.JpushId
	sn.DevicesVersion = &co.DevicesVersion
	sn.AppstoreVersion = &co.AppstoreVersion
	sn.StoreVersion = &co.StoreVersion
	err = global.GVA_DB.Save(&sn).Error
	if err != nil {
		response.FailWithMessage("更新失败", c)
		return
	}
	response.OkWithMessage("成功", c)
	return
}

func (s *SnApi) getInfo(c *gin.Context) {

}

//
// GetDeveloper
//  @Description: 获取开发者管控信息
//  @receiver s
//  @param c
//
func (s *SnApi) GetDeveloper(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	type result struct {
		IsDeveloper *int64 `gorm:"column:is_developer;type:tinyint(1);comment:开发者模式 0关闭  1开启" json:"is_developer"`
	}
	var res result
	err = global.GVA_DB.Model(&system.Sn{}).Select("is_developer").Where("value = ?", co.Sn).First(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(res, c)
	return
}

func (s *SnApi) GetAppCoordinate(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	if rs.Data == nil || rs.Data == "" {
		response.FailWithMessage("该设备没有设置批次", c)
		return
	}

	var res system.AppCoordinate
	where := fmt.Sprintf("find_in_set('%s',batch)", rs.Data)
	err = global.GVA_DB.Model(&system.AppCoordinate{}).Where(where).First(&res).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	response.OkWithData(res, c)
}

//
// GetWifi
//  @Description: 获取wifi白名单
//  @receiver s
//  @param c
//
func (s *SnApi) GetWifi(c *gin.Context) {

	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var sn system.Sn
	err = global.GVA_DB.Model(&system.Sn{}).Where("value=?", co.Sn).First(&sn).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}

	var wifi system.Wifi
	where := fmt.Sprintf("find_in_set('%s',batch)", *sn.Batch)
	err = global.GVA_DB.Model(&system.Wifi{}).Where(where).First(&wifi).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}

	type wifiName struct {
		Name string `json:"name"`
	}

	var name []wifiName
	json.Unmarshal([]byte(*wifi.Wifi), &name)

	var deWifi system.WifiDefault
	global.GVA_DB.Model(&system.WifiDefault{}).Where("admin_id=?", sn.AdminID).First(&deWifi)

	if deWifi.Name != nil {
		var deName wifiName
		deName.Name = *deWifi.Name
		name = append(name, deName)
	}
	response.OkWithData(name, c)
}

//
// GetUserInfo
//  @Description: 生成用户的qid
//  @receiver s
//  @param c
//
func (s *SnApi) GetUserInfo(c *gin.Context) {
	var ac systemReq.GetAccount
	err := c.ShouldBind(&ac)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(ac, utils.GetUserInfoVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var sn system.Sn
	//校验是手机号还是sn
	if utils.CheckMobile(ac.Account) {
		if len(ac.Password) != 6 {
			response.FailWithMessage("密码错误", c)
			return
		}
		var phoneAccount system.PhoneAccount
		err = global.GVA_DB.Model(&system.PhoneAccount{}).Where("phone = ?", ac.Account).Where("del = -1").First(&phoneAccount).Error
		if err != nil {
			response.FailWithMessage("账号不存在", c)
			return
		}
		if phoneAccount.Password != ac.Password {
			response.FailWithMessage("密码错误", c)
			return
		}

	} else {
		err = global.GVA_DB.Model(&system.Sn{}).Where("value = ?", ac.Account).First(&sn).Error
	}
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	//校验是否可生成qid
	var snQid system.SnQid
	err = global.GVA_DB.Model(&system.SnQid{}).Where("sn = ?", ac.Account).Where("del = -1").First(&snQid).Error
	if err != nil {
		response.FailWithMessage("该账号不可生成qid,请联系管理员设置", c)
		return
	}
	status := snService.GetQidStatus(&snQid)
	isExpire := -1 // 是否过期 1：是 -1: 否
	if status == 3 || status == 5 {
		isExpire = 1
	}

	if snQid.UserActive != 1 {
		response.OkWithData(&systemRes.GetUseRes{Qid: snQid.Qid, Uid: snQid.UID, UserActive: snQid.UserActive, IsTeacher: snQid.IsTeacher, IsExpire: 1}, c)
		return
	}
	if len(snQid.Qid) > 0 {
		response.OkWithData(&systemRes.GetUseRes{Qid: snQid.Qid, Uid: snQid.UID, UserActive: snQid.UserActive, IsTeacher: snQid.IsTeacher, IsExpire: isExpire}, c)
		return
	}

	//生成qid
	qid, err := snService.CreateQid(snQid.AccountType)

	//请求赶考创建用户
	createReq := systemReq.CreateUserReq{}
	createReq.AppID = global.GVA_CONFIG.System.GanKaoAppID
	createReq.UID = qid
	createReq.Timestamp = time.Now().Unix()
	ganKaoRes, err := ganKaoService.CreateUser(&createReq)
	if err != nil {
		global.GVA_LOG.Error(err.Error(), zap.String("account", ac.Account), zap.String("Qid", qid))
		response.FailWithMessage("赶考创建用户失败", c)
		return
	}

	//更改数据库
	snQid.Qid = qid
	snQid.CreateTime = time.Now().Unix()
	snQid.UID = ganKaoRes.Data.GanKaoUID
	err = global.GVA_DB.Save(&snQid).Error
	if err != nil {
		response.FailWithMessage("保存失败", c)
		return
	}

	//创建成功后加入延迟队列到期自动激活
	active := systemReq.QidActive{
		Sn:  snQid.Sn,
		Qid: snQid.Qid,
		Uid: snQid.UID,
	}
	info := system2.DelayInfo{
		JobPoolKey:         "active_pool_key_",
		BaseDelayBucketKey: "active_delay_bucket",
		BaseReadyQueueKey:  "active_ready_queue",
		DelayAddTime:       86400 * 7, //延迟7天后自动正式正式激活
	}
	var data system2.RedisJobData
	conn := context.Background()
	data.Body = active
	data.SetJobPool(1, info, conn)
	response.OkWithData(&systemRes.GetUseRes{Qid: snQid.Qid, Uid: snQid.UID, UserActive: snQid.UserActive, IsTeacher: snQid.IsTeacher, IsExpire: isExpire}, c)
	return
}

//
// SetUserActive
//  @Description: 用户确认激活，进行状态记录
//  @receiver s
//  @param c
//
func (s *SnApi) SetUserActive(c *gin.Context) {
	var sn systemReq.CommonSn
	err := c.ShouldBind(&sn)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(sn, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var snQid system.SnQid
	err = global.GVA_DB.Model(&system.SnQid{}).Where("sn = ?", sn.Sn).Where("del = -1").First(&snQid).Error
	if err != nil {
		response.FailWithMessage("该sn不可生成qid,请联系管理员设置", c)
		return
	}
	snQid.UserActive = 1
	err = global.GVA_DB.Save(&snQid).Error
	if err != nil {
		response.FailWithMessage("上报失败", c)
		return
	}
	response.Ok(c)
	return
}

//
// GetWhiteMsgApp
//  @Description: 获取app消息通知白名单
//  @receiver s
//  @param c
//
func (s *SnApi) GetWhiteMsgApp(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var rs utils.CacheResult
	rs = utils.GetRedisCacheField("sn", "value", co.Sn, "batch")
	if rs.Data == nil || rs.Data == "" {
		response.FailWithMessage("该设备没有设置批次", c)
		return
	}
	var appStatus system.AppStatus
	err = global.GVA_DB.Where("batch_id=?", rs.Data).Where("del=-1").First(&appStatus).Error
	if err != nil {
		response.FailWithMessage("没有数据", c)
		return
	}
	appIdArr := strings.Split(appStatus.AppIds, ",")
	systemAppIdArr := strings.Split(appStatus.SystemAppIds, ",")
	var app []system.App
	var systemApp []system.SystemApp

	global.GVA_DB.Where("app_id IN ?", appIdArr).Find(&app)
	global.GVA_DB.Where("id IN ?", systemAppIdArr).Find(&systemApp)

	var packageName []string

	for _, v := range app {
		packageName = append(packageName, *v.Bg)
	}
	for _, v := range systemApp {
		packageName = append(packageName, *v.Package)
	}
	type result struct {
		PackageName string `json:"package_name"`
	}
	var res result
	if len(packageName) == 0 {
		res.PackageName = ""
		response.OkWithDetailed(res, "success", c)
		return
	}
	res.PackageName = strings.Join(packageName, ",")
	response.OkWithDetailed(res, "success", c)
	return
}

func (s *SnApi) GetAllMac(c *gin.Context) {
	var rsh systemReq.RefreshMac
	err := c.ShouldBind(&rsh)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if rsh.Limit == 0 {
		rsh.Limit = 50
	}

	cacheKey := "GetAllMacKey"
	start, err := global.GVA_REDIS.Get(context.Background(), cacheKey).Int()
	if err != nil {
		start = 21
	}
	var smac []system.SnCreateMac
	err = global.GVA_DB.Where("id > ?", start).Order("id ASC").Limit(rsh.Limit).Find(&smac).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if len(smac) == 0 {
		response.FailWithMessage("已经记录完毕", c)
		return
	}

	for _, v := range smac {
		global.GVA_REDIS.SAdd(context.Background(), "macSetCacheKey", *v.Mac)
		start = int(v.ID)
	}

	dr, err := utils.ParseDuration("7d")
	if err != nil {
		response.FailWithMessage("时间错误", c)
		return
	}
	global.GVA_REDIS.Set(context.Background(), cacheKey, start, dr)
	response.OkWithMessage("成功", c)
	return
}

//
// SetGanKaoInfo
//  @Description: 上报赶考信息
//  @receiver s
//  @param c
//
func (s *SnApi) SetGanKaoInfo(c *gin.Context) {
	var gki systemReq.GanKaoInfo
	err := c.ShouldBind(&gki)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	err = utils.Verify(gki, utils.GanKaoInfoVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var qidInfo system.SnQid
	err = global.GVA_DB.Model(&system.SnQid{}).Where("qid = ?", gki.Qid).First(&qidInfo).Error
	if err != nil {
		response.FailWithMessage("账号不存在", c)
		return
	}
	//todo 这里要校验数据
	qidInfo.Avatar, qidInfo.Username, qidInfo.Grade, qidInfo.Sex, qidInfo.Address = gki.Avatar, gki.Username, gki.Grade, gki.Sex, gki.Address
	err = global.GVA_DB.Save(&qidInfo).Error
	if err != nil {
		response.FailWithMessage("设置失败", c)
		msg := fmt.Sprintf("设置赶考信息失败qid为：%s", gki.Qid)
		global.GVA_LOG.Info(msg, zap.String("error", err.Error()))
		return
	}
	qidRes := systemRes.GanKanInfoResponse{
		Qid:      gki.Qid,
		Username: gki.Username,
		Avatar:   gki.Avatar,
		Grade:    gki.Grade,
		Sex:      gki.Sex,
		Address:  gki.Address,
	}
	cacheKey := "ganKaoInfo@" + gki.Qid
	dr, _ := utils.ParseDuration("7d")
	global.GVA_REDIS.Set(context.Background(), cacheKey, &qidRes, dr)
	response.OkWithData(qidRes, c)
	return
}

//
// GetGanKaoInfo
//  @Description: 获取赶考信息
//  @receiver s
//  @param c
//
func (s *SnApi) GetGanKaoInfo(c *gin.Context) {
	var ggk systemReq.GetGanKao
	err := c.ShouldBind(&ggk)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(ggk, utils.GanKaoInfoVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	qidRes := systemRes.GanKanInfoResponse{}

	cacheKey := "ganKaoInfo@" + ggk.Qid
	err = global.GVA_REDIS.Get(context.Background(), cacheKey).Scan(&qidRes)
	if err == nil {
		response.OkWithData(qidRes, c)
		return
	}

	err = global.GVA_DB.Model(&system.SnQid{}).Where("qid = ?", ggk.Qid).First(&qidRes).Error
	if err != nil {
		response.FailWithMessage("账号不存在", c)
		return
	}
	dr, err := utils.ParseDuration("7d")
	global.GVA_REDIS.Set(context.Background(), cacheKey, &qidRes, dr)
	response.OkWithData(qidRes, c)
	return
}

func (s *SnApi) LoginGanKao(c *gin.Context) {
	var login systemReq.LogInGanKao
	err := c.ShouldBind(&login)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(login, utils.LoginGanKaoVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var qidInfo system.SnQid
	err = global.GVA_DB.Model(&system.SnQid{}).Where("qid = ?", login.Qid).First(&qidInfo).Error
	if err != nil {
		response.FailWithMessage("账号不存在", c)
		return
	}
	qidInfo.LoginSn, qidInfo.LoginTime = login.LoginSn, time.Now().Unix()
	err = global.GVA_DB.Save(qidInfo).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.Ok(c)
	return
}

//
// ReportSnTime
//  @Description: 上报设备使用时长
//  @receiver s
//  @param c
//
func (s *SnApi) ReportSnTime(c *gin.Context) {
	var st systemReq.SnTime
	err := c.ShouldBind(&st)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(st, utils.SnUseTimeVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	//获取精确到当前的时间戳
	t := time.Now()
	newTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
	dayTime := newTime.Unix()
	cacheKey := fmt.Sprintf("snDayUseTime%s%d", st.Sn, dayTime)
	dr, _ := utils.ParseDuration("1d")
	setRes := global.GVA_REDIS.SetNX(context.Background(), cacheKey, st.UseTime, dr)

	//上报数据
	rep := system.SnUseTime{
		Sn:      st.Sn,
		Day:     dayTime,
		UseTime: st.UseTime,
	}
	if setRes.Val() {
		rep.CreateTime = t.Unix()
		err = global.GVA_DB.Create(&rep).Error
		if err != nil {
			response.FailWithMessage("上报失败1", c)
			return
		}
	} else {
		err = global.GVA_DB.Model(&system.SnUseTime{}).Where("sn = ?", st.Sn).Where("day = ?", dayTime).Updates(rep).Error
		if err != nil {
			response.FailWithMessage("上报失败2", c)
			return
		}
	}
	response.Ok(c)
	return
}

//
// NewReportTime
//  @Description: 上报设备使用时长
//  @receiver s
//  @param c
//
func (s *SnApi) NewReportTime(c *gin.Context) {
	//校验数据
	var nst systemReq.NewSnTime
	err := c.ShouldBind(&nst)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(nst, utils.SnUseTimeVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	//处理数据
	type DayTimes struct {
		Date       string `json:"date"`
		ScreenTime int64  `json:"screenTime"`
	}
	var dayTimes []DayTimes
	json.Unmarshal([]byte(nst.UseTime), &dayTimes)

	var rep []system.SnUseTime
	var delId []int
	for _, v := range dayTimes {
		v.Date += " 00:00:00"
		loc, _ := time.LoadLocation("Local")
		date, _ := time.ParseInLocation("2006-01-02 15:04:05", v.Date, loc)
		unixTime := date.Unix()
		t := system.SnUseTime{
			Sn:      nst.Sn,
			Day:     unixTime,
			UseTime: v.ScreenTime,
		}
		rep = append(rep, t)
		cacheKey := fmt.Sprintf("snDayUseTime:%s:%d", nst.Sn, unixTime)
		if id, err := global.GVA_REDIS.Get(context.Background(), cacheKey).Int(); err == nil {
			delId = append(delId, id)
		}
	}
	//删除已存在的记录然后添加
	if len(delId) > 0 {
		global.GVA_DB.Where("id IN ?", delId).Delete(&system.SnUseTime{})
	}
	err = global.GVA_DB.Create(&rep).Error
	if err != nil {
		global.GVA_LOG.Info("上报设备使用时间错误", zap.String("err", err.Error()))
		response.FailWithMessage("上报出错", c)
		return
	}
	//数据库记录后添加缓存防止重复上报
	dr, _ := utils.ParseDuration("30d")
	for _, v := range rep {
		cacheKey := fmt.Sprintf("snDayUseTime:%s:%d", nst.Sn, v.Day)
		global.GVA_REDIS.Set(context.Background(), cacheKey, v.ID, dr)
	}
	response.OkWithData(rep, c)
	return
}

func (s *SnApi) GetSnClassAndTag(c *gin.Context) {
	var co systemReq.CommonSn
	err := c.ShouldBind(&co)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(co, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var sn system.Sn
	err = global.GVA_DB.Where("value = ?", co.Sn).First(&sn).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	where := fmt.Sprintf("find_in_set('%s',batch_ids) OR find_in_set('%d',child_admin)", *sn.Batch, sn.AdminID)

	var conClass []system.ContentClass
	err = global.GVA_DB.Model(&system.ContentClass{}).Where(where).Where("del=-1").Preload("ContentCollect").Find(&conClass).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var collectIdArr []int64
	for _, class := range conClass {
		for _, collect := range class.ContentCollect {
			collectIdArr = append(collectIdArr, collect.ID)
		}
	}

	var totalContent []system.SelfContent
	for index, class := range conClass {
		var classContent []system.SelfContent
		where = fmt.Sprintf("find_in_set('%d', class_ids)", class.ID)
		global.GVA_DB.Model(&system.SelfContent{}).Where(where).Where("del=-1").Find(&classContent)
		conClass[index].Content = classContent
		//todo 有其他二位数组合并的方法吗?
		for _, content := range classContent {
			totalContent = append(totalContent, content)
		}
	}

	collectMap := make(map[int64][]system.SelfContent)
	for _, id := range collectIdArr {
		var collectContent []system.SelfContent
		where = fmt.Sprintf("find_in_set('%d', collect_ids)", id)
		global.GVA_DB.Model(&system.SelfContent{}).Where(where).Where("del=-1").Find(&collectContent)
		collectMap[id] = collectContent
		for _, content := range collectContent {
			totalContent = append(totalContent, content)
		}
	}

	for i, class := range conClass {
		for j, collect := range class.ContentCollect {
			if collectMap[collect.ID] != nil {
				conClass[i].ContentCollect[j].Content = collectMap[collect.ID]
			}
		}
	}

	//没有分配分类,合集,标签 的内容展示在所有部分
	var selfContent []system.SelfContent
	global.GVA_DB.Where(where).Where("del=?", -1).Find(&selfContent)
	for _, content := range selfContent {
		totalContent = append(totalContent, content)
	}

	var contentArr []system.SelfContent
	contentIdMap := make(map[int64]bool)
	for _, content := range totalContent {
		if !contentIdMap[content.ContentID] {
			contentArr = append(contentArr, content)
		}
		contentIdMap[content.ContentID] = true
	}

	var conTag []system.ContentTag
	where = fmt.Sprintf("find_in_set('%s',batch_ids) OR find_in_set('%d',child_admin)", *sn.Batch, sn.AdminID)
	global.GVA_DB.Model(&system.ContentTag{}).Where(where).Where("del=-1").Find(&conTag)

	var miniPro system.MiniProgramInfo
	whereBatch := fmt.Sprintf("find_in_set('%s',batch)", *sn.Batch)
	global.GVA_DB.Model(&system.MiniProgramInfo{}).Where(whereBatch).Where("del=-1").First(&miniPro)

	var result systemRes.ClassAndTagRes
	result.Class = conClass
	result.Tag = conTag
	result.Logo = miniPro.Logo
	result.TotalContent = contentArr
	response.OkWithData(result, c)
	return
}

func (s *SnApi) GetSnRead(c *gin.Context) {
	var sre systemReq.SnRead
	err := c.ShouldBind(&sre)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(sre, utils.SnReadVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var sn system.Sn
	sn.Value = sre.Sn
	err = global.GVA_DB.First(&sn).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	cacheKey := fmt.Sprintf("snRead@%s", sre.Sn)
	dr, _ := utils.ParseDuration("1d")
	setRes := global.GVA_REDIS.SetNX(context.Background(), cacheKey, 1, dr)

	if setRes.Val() { //首次上报添加记录
		var snRead system.SnReadContent
		switch sre.Type {
		case 1: //self_content 表id
			snRead.ContentID = sre.Id
		case 2:
			//snRead.HomeworkID = sre.Id
		}
		snRead.CreateTime = time.Now().Unix()
		snRead.Sn = sre.Sn
		snRead.SnID = sn.ID
		err = global.GVA_DB.Model(&system.SnReadContent{}).Save(&snRead).Error
		if err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
	} else {
		global.GVA_REDIS.Incr(context.Background(), cacheKey)
	}

	response.Ok(c)
	return
}

//这个方法只是测试延迟队列
func (s *SnApi) ActiveGanKanProcess(c *gin.Context) {
	var common systemReq.CommonSn
	err := c.ShouldBind(&common)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var snQid system.SnQid
	err = global.GVA_DB.Where("sn", common.Sn).Where("del", -1).First(&snQid).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	active := systemReq.QidActive{
		Sn:  common.Sn,
		Qid: snQid.Qid,
		Uid: snQid.UID,
	}
	var data system2.RedisJobData
	conn := context.Background()
	data.Body = active
	info := system2.DelayInfo{
		JobPoolKey:         "active_pool_key_",
		BaseDelayBucketKey: "active_delay_bucket",
		BaseReadyQueueKey:  "active_ready_queue",
		DelayAddTime:       5,
	}
	data.SetJobPool(1, info, conn)
	response.Ok(c)
	return
}

func (s *SnApi) TestMqttPulish(c *gin.Context) {

	num := 10
	for i := 0; i < num; i++ {
		text := fmt.Sprintf("Message %d", i)
		token := global.GVA_MQTT.Publish("Bob", 0, false, text)
		token.Wait()
		time.Sleep(time.Second)
	}
	response.Ok(c)
	return
}

func (s *SnApi) TestSubscribe(c *gin.Context) {
	topic := "Bob"
	token := global.GVA_MQTT.Subscribe(topic, 1, nil)
	token.Wait()
	fmt.Printf("Subscribed to topic: %s", topic)
	response.Ok(c)
	return
}

func (s *SnApi) GetLoginType(c *gin.Context) {
	var common systemReq.CommonSn
	err := c.ShouldBind(&common)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(common, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var sn system.Sn
	err = global.GVA_DB.Where("value = ?", common.Sn).First(&sn).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var loginType system.AccountLoginType
	whereBatch := fmt.Sprintf("find_in_set('%s',batch_ids) OR find_in_set('%d',child_admin)", *sn.Batch, sn.AdminID)

	err = global.GVA_DB.Model(&loginType).Where(whereBatch).Where("del=-1").Order("id DESC").First(&loginType).Error

	type res struct {
		ID   int64 `json:"id"`
		Type int64 `json:"type"`
	}
	var result res
	if err != nil {
		result.ID = 0
		result.Type = 1
	} else {
		result.ID = loginType.ID
		result.Type = loginType.Type
	}
	response.OkWithData(result, c)
	return
}

//
// GetEyesConfig
//  @Description: 获取护眼配置
//  @receiver s
//  @param c
//
func (s *SnApi) GetEyesConfig(c *gin.Context) {
	var common systemReq.CommonSn
	err := c.ShouldBind(&common)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(common, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	//截取sn的前五位
	var fiveSn string
	fiveSn = common.Sn[0:5]
	//获取配置
	var res systemRes.EyesConfigRes
	cacheKey := fmt.Sprintf("eyesConfig@%s", fiveSn)
	err = global.GVA_REDIS.Get(context.Background(), cacheKey).Scan(&res)
	if err == nil {
		response.OkWithData(res, c)
		return
	}
	err = global.GVA_DB.Model(&system.EyesConfig{}).Where("five_sn = ?", fiveSn).Where("del = -1").First(&res).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	dr, err := utils.ParseDuration("30d")
	global.GVA_REDIS.Set(context.Background(), cacheKey, &res, dr)
	response.OkWithData(res, c)
	return
}

//恢复出厂设置时清空应用安装记录
func (s *SnApi) ClearBeforeRestore(c *gin.Context) {
	var common systemReq.CommonSn
	err := c.ShouldBind(&common)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(common, utils.SnVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	global.GVA_DB.Model(&system.AppInstallLog{}).Where("sn=?", common.Sn).Delete(&system.AppInstallLog{})
	response.Ok(c)
	return
}
